/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package numeros;

import buscaemamplitude.Estado;
import buscaemamplitude.EstadoObject;
import buscaemamplitude.Problema;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Cristian
 */
public class ProblemaNumeros implements Problema {

    private short[][] tabuleiroInicial = {{1, 2, 3}, {4, 5, 6}, {8, 7, 0}};
    private short[][] tabuleiroFinal = {{1, 2, 3}, {4, 5, 6}, {7, 8, 0}};

    @Override
    public EstadoObject getEstadoInicial() {
        return new EstadoObjectNumeros(tabuleiroInicial);
    }

    @Override
    public EstadoObject getEstadoFinal() {
        return new EstadoObjectNumeros(tabuleiroFinal);
    }

    @Override
    public List<Estado> explorar(EstadoObject estadoObject) {
        short[][] tabuleiro = ((EstadoObjectNumeros) estadoObject).getTabuleiro();
        List<Estado> list = new ArrayList<Estado>();

        for (int i = 0; i < tabuleiro.length; i++) {
            for (int j = 0; j < tabuleiro.length; j++) {
                if (tabuleiro[i][j] == 0) {
                    if (i > 0) { //cima
                        short[][] filho = clonarTabuleiro(tabuleiro);
                        filho[i][j] = tabuleiro[i - 1][j];
                        filho[i - 1][j] = 0;
                        list.add(new Estado(new EstadoObjectNumeros(filho), 1, 1));
                    }
                    if (i < tabuleiro.length - 1) { //baixo
                        short[][] filho = clonarTabuleiro(tabuleiro);
                        filho[i][j] = tabuleiro[i + 1][j];
                        filho[i + 1][j] = 0;
                        list.add(new Estado(new EstadoObjectNumeros(filho), 1, 1));
                    }
                    if (j > 0) { //esquerda
                        short[][] filho = clonarTabuleiro(tabuleiro);
                        filho[i][j] = tabuleiro[i][j - 1];
                        filho[i][j - 1] = 0;
                        list.add(new Estado(new EstadoObjectNumeros(filho), 1, 1));
                    }
                    if (j < tabuleiro.length - 1) { //direita
                        short[][] filho = clonarTabuleiro(tabuleiro);
                        filho[i][j] = tabuleiro[i][j + 1];
                        filho[i][j + 1] = 0;
                        list.add(new Estado(new EstadoObjectNumeros(filho), 1, 1));
                    }

                    return list;
                }
            }
        }

        return list;
    }

    public static short[][] clonarTabuleiro(short[][] tabuleiro) {
        short[][] target = new short[tabuleiro.length][tabuleiro.length];
        for (int i = 0; i < tabuleiro.length; i++) {
            System.arraycopy(tabuleiro[i], 0, target[i], 0, tabuleiro.length);
        }
        return target;
    }

    @Override
    public float getCustoEstimado(EstadoObject estadoObject) {
        short[][] estadoAtual = ((EstadoObjectNumeros) estadoObject).getTabuleiro();

        float v = 0;
        boolean encontrou1;
        boolean encontrou2;

        for (int i = 0; i < (estadoAtual.length ^ 2); i++) {
            encontrou1 = false;
            for (int j = 0; j < estadoAtual.length && !encontrou1; j++) {
                for (int k = 0; k < estadoAtual.length && !encontrou1; k++) {
                    if (estadoAtual[j][k] == i) {
                        encontrou1 = true;
                        encontrou2 = false;
                        for (int m = 0; m < tabuleiroFinal.length && !encontrou2; m++) {
                            for (int n = 0; n < tabuleiroFinal.length && !encontrou2; n++) {
                                if (tabuleiroFinal[m][n] == i) {
                                    encontrou2 = true;
                                    v += Math.abs(j - m) + Math.abs(k - n);
                                }
                            }
                        }
                    }
                }
            }
        }
        return v;
    }
}
